package cn.itsource.user.service.impl;

import cn.itsource.basic.domain.dto.SendSmsDto;
import cn.itsource.basic.exception.CustomException;
import cn.itsource.basic.util.MD5Utils;
import cn.itsource.basic.util.StrUtils;
import cn.itsource.user.domain.Logininfo;
import cn.itsource.user.domain.User;
import cn.itsource.user.mapper.LogininfoMapper;
import cn.itsource.user.mapper.UserMapper;
import cn.itsource.user.service.IUserService;
import cn.itsource.basic.service.impl.BaseServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import sun.security.util.Password;

import java.util.Date;
import java.util.function.DoubleToLongFunction;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author itsource
 * @since 2022-08-09
 */
@Service
@Transactional
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private UserMapper userMapper;

    /**
     * 手机号注册
     * @param dto
     */
    @Override
    public void phoneRegister(SendSmsDto dto) {
//        1. 非空校验
        if(StringUtils.isEmpty(dto.getMobile())
                || StringUtils.isEmpty(dto.getPassword())
                || StringUtils.isEmpty(dto.getConfirmPassword())){
            throw new CustomException("参数异常！");
        }
//        2. 密码一致性校验
        if(!dto.getPassword().equals(dto.getConfirmPassword())){
            throw new CustomException("密码错误！");
        }
//        3. 用前端传递的手机号拼接业务键，去redis中查询短信验证码
        String smsCodeKey = dto.getMobile()+":register";
        Object smsCodeValue = redisTemplate.opsForValue().get(smsCodeKey);
        if(smsCodeValue == null) {
            //        1. 如果查不到，返回自定义异常，短信验证码过期了
            throw new CustomException("短信验证码已过期！");
        }
//        4. 查到就和前端传递的验证码进行比对
        String smsCode = smsCodeValue.toString().split(":")[0]; //smsCode-是短信验证码字串
        if(!smsCode.equals(dto.getSmsCode())){
//        1. 不一致，返回自定义异常，验证码错误
            throw new CustomException("短信验证码错误！");
        }
//        5. 生成盐值随机字符串（32位）保留
        String saltValue = StrUtils.getComplexRandomString(32);
//        6. 使用MD5工具类加密密码（密码需要拼接盐值一起加密）
        String md5Password = MD5Utils.encrypByMd5(saltValue + dto.getPassword());

//        7. 构建user和login_info对象，初始化参数
        User user = initUser(dto.getMobile(),saltValue,md5Password);
        Logininfo logininfo = user2Longininfo(user);
//        8. 先保存login_info，获取自增id
        logininfoMapper.add(logininfo);
//        9. 再保存user
        user.setLogininfoId(logininfo.getId());
        userMapper.add(user);
    }

    /**
     * 邮箱号注册
     * @param dto
     */
    @Override
    public void emailRegister(SendSmsDto dto) {
        //        1. 非空校验
        if(StringUtils.isEmpty(dto.getEmail())
                || StringUtils.isEmpty(dto.getPassword())
                || StringUtils.isEmpty(dto.getConfirmPassword())){
            throw new CustomException("参数异常！");
        }
//        2. 密码一致性校验
        if(!dto.getPassword().equals(dto.getConfirmPassword())){
            throw new CustomException("密码错误！");
        }
//        3. 用前端传递的手机号拼接业务键，去redis中查询短信验证码
        String emailCodeKey = dto.getEmail()+":register";
        Object emailCodeValue = redisTemplate.opsForValue().get(emailCodeKey);
        if(emailCodeValue == null) {
            //        1. 如果查不到，返回自定义异常，短信验证码过期了
            throw new CustomException("邮箱验证码已过期！");
        }
//        4. 查到就和前端传递的验证码进行比对
        String emailCode = emailCodeValue.toString().split(":")[0]; //smsCode-是短信验证码字串
        if(!emailCode.equals(dto.getEmailCode())){
//        1. 不一致，返回自定义异常，验证码错误
            throw new CustomException("邮箱验证码错误！");
        }
//        5. 生成盐值随机字符串（32位）保留
        String saltValue = StrUtils.getComplexRandomString(32);
//        6. 使用MD5工具类加密密码（密码需要拼接盐值一起加密）
        String md5Password = MD5Utils.encrypByMd5(saltValue + dto.getPassword());

//        7. 构建user和login_info对象，初始化参数
        User user = initUser3(dto.getEmail(),saltValue,md5Password);
        Logininfo logininfo = user4Longininfo(user);
//        8. 先保存login_info，获取自增id
        logininfoMapper.add(logininfo);
//        9. 再保存user
        user.setLogininfoId(logininfo.getId());
        userMapper.add(user);
    }

    private User initUser3(String email, String salt, String md5Password) {
        User user = new User();
        user.setEmail(email);
        user.setSalt(salt);
        user.setPassword(md5Password);
        user.setState(1);
        user.setCreatetime(new Date());
        return user;
    }

    private Logininfo user4Longininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);//copyProperties(要拷贝的源对象，拷贝到的目标对象)
        logininfo.setDisable(1);
        logininfo.setType(1);
        return logininfo;
    }

    private Logininfo user2Longininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);//copyProperties(要拷贝的源对象，拷贝到的目标对象)
        logininfo.setDisable(1);
        logininfo.setType(1);
        return logininfo;
    }

    private User initUser(String mobile, String salt, String md5Password) {
        User user = new User();
        user.setPhone(mobile);
        user.setSalt(salt);
        user.setPassword(md5Password);
        user.setState(1);
        user.setCreatetime(new Date());
        user.setUsername(mobile);
        return user;
    }
}
